package com.ms.orm.meta;

/**
 * @author .
 */

import java.io.Serializable;
import java.util.List;
import java.util.function.Function;

import static java.util.stream.Collectors.toList;

/**
 * 分页 Page 对象接口
 *
 * @author hubin
 * @since 2018-06-09
 */
public interface IPage<T> extends Serializable {

    /**
     * 获取排序信息，排序的字段和正反序
     * @return 排序信息
     */
    List<SortItem> orders();



    /**
     * 进行 count 查询 【 默认: true 】
     * @return true 是 / false 否
     */
    default boolean searchCount() {
        return true;
    }



    /**
     * 计算当前分页偏移量(即当前页 记录开始位置)
     * offset = 前面一页 * pageSize
     * @return
     */
    default long offset() {
        long current = getCurrent();
        if (current <= 1L) {
            return 0L;
        }
        return Math.max((current - 1) * getSize(), 0L);
    }

    /**
     * 最大每页分页数限制,优先级高于分页插件内的 maxLimit
     * @return
     */
    default Long maxLimit() {
        return null;
    }


    /**
     * 获取分页总页数
     * 分页总页数 = 记录总数/每页记录数
     * @return
     */
    default long getTotalPage() {
        if (getSize() == 0) {
            return 0L;
        }
        long pages = getTotal() / getSize();
        if (getTotal() % getSize() != 0) {
            //记录总数 对每页记录数据 取模，如果不等于0，表示还有一页数据，但该数据不满一页
            pages++;
        }
        return pages;
    }


    /**
     * 设置总分页数，避免序列化出错
     * @param pages
     * @return
     */
    default IPage<T> setTotalPage(long pages) {
        // to do nothing
        return this;
    }

    /**
     * 分页记录列表
     * @return 分页对象记录列表
     */
    List<T> getRecords();


    /**
     * 设置分页记录列表
     * @param records
     * @return
     */
    IPage<T> setRecords(List<T> records);

    /**
     * 当前满足条件总行数
     * @return 总条数
     */
    long getTotal();

    /**
     * 设置当前满足条件总行数
     * @param total
     * @return
     */
    IPage<T> setTotal(long total);

    /**
     * 获取每页显示条数
     * @return 每页显示条数
     */
    long getSize();


    /**
     * 设置每页显示条数
     * @param size
     * @return
     */
    IPage<T> setSize(long size);


    /**
     * 获取当前页
     * @return
     */
    long getCurrent();


    /**
     * 设置当前页
     * @param current
     * @return
     */
    IPage<T> setCurrent(long current);

    /**
     * IPage 的泛型转换
     * @param mapper 转换函数
     * @param <R>    转换后的泛型
     * @return 转换泛型后的 IPage
     */
    @SuppressWarnings("unchecked")
    default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
        List<R> collect = this.getRecords().stream().map(mapper).collect(toList());
        return ((IPage<R>) this).setRecords(collect);
    }

}
